// 获得 DES S 盒的差分分布表
package main

import (
	"DES/DES"
	"fmt"
)

var DifferSearch = possibleDiffer()

// 获得指定 的 S盒 的差分表 6 进 4 出
func DifferSTable(index int) [][]uint8 {
	result := make([][]uint8, 64)
	for i := 0; i < 64; i++ {
		tmp := make([]uint8, 16)
		result[i] = tmp
	}
	for inputDiff := uint8(0); inputDiff < 64; inputDiff ++ {
		for input := uint8(0); input < 64; input ++ {
			otherInput := inputDiff ^ input
			output := DES.Single_Sbox(input, index)
			otherOutput := DES.Single_Sbox(otherInput, index)
			outputDiffer := output ^ otherOutput
			result[inputDiff][outputDiffer] ++
		}
	}
	return result
}

// 打印差分表
func printTable(tt *[][]uint8) {
	for i := 0; i < len(*tt); i++ {
		fmt.Println((*tt)[i])
	}
}

func possibleDiffer() [][][]uint8 {
	tmp := make([][][]uint8, 8)
	for i := 0; i < 8; i++ {
		k := make([][]uint8, 64)
		for j := 0; j < 64; j++ {
			k[j] = make([]uint8, 2)
		}
		tmp[i] = k
	}
	for i := 1; i < 9; i++ {
		diffTable := DifferSTable(i)
		for j := 0; j < 64; j++ {
			max := uint8(0)
			t := uint8(0)
			for k := uint8(0); k < 16; k++ {
				if diffTable[j][k] > max {
					max = diffTable[j][k]
					t = k
				}
			}
			tmp[i - 1][j][0] = t
			tmp[i - 1][j][1] = max
		}
	}
	return tmp
}

// 对指定的S盒，得到该输入差分最可能得到的输出差分, 及其概率
func GetPossibleDiffer(diff uint8, index int) (uint8, uint8){
	return DifferSearch[index - 1][diff][0], DifferSearch[index - 1][diff][1]
}

/*
 **通过一轮F函数后差分的变化 输入为32位差分，输出为32位差分
 **F函数中 扩展置换E和p盒置换对差分的影响是可以 100% 确认的。
 **此函数输出通过F函数可能的结果，及其概率
 */
func DifferF(input uint32) (output uint32, p []int) {
	tmp := DES.EChange(input)
	for i := 0; i < 8; i++ {
		if output != 0 {
			output <<= 4
		}
		t := (tmp >> (6 * (7 - i))) & 63
		re, tp := GetPossibleDiffer(uint8(t), i + 1)
		if tp != 64 {
			p = append(p, int(tp))
		}
		output |= uint32(re)
		//output <<= 4
	}
	output = DES.PChange(output)
	return
}

func FindDifferPath(linput uint32, rinput uint32) {
	for i := 0; i < 5; i++ {
		tre, tp := DifferF(rinput)
		fmt.Println(DES.DeToHex(tre), "	", DES.DeToHex(rinput), "	", tp)
		tmp := rinput
		rinput = tre ^ linput
		linput = tmp
	}
}

func main() {
	FindDifferPath(DES.HexToDe("405c0000"), DES.HexToDe("04000000"))
}